from datetime import datetime
from loguru import logger
from typing import Optional, List

from sqlalchemy import or_
from sqlalchemy.dialects.postgresql import insert
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import Session
from sqlalchemy.orm.attributes import flag_modified

from apis_module.jsonvo.reviews_vo import ReviewsListQueryModel, ReviewsViewModel, ReviewsImagesRequest
from apis_module.model.look_model import ReviewsLookModel
from apis_module.model.reviews_model import ReviewsModel


class ReviewsDao:
    @classmethod
    def get_reviews_list(cls, db: Session, query_model: ReviewsListQueryModel) -> Optional[List]:
        """
        点评列表查询方法
        :param db: ORM
        :param query_model: 查询参数集
        :return: 分页列表
        """
        offset = (query_model.page_num - 1) * query_model.page_size
        reviews_list = db.query(ReviewsModel) \
            .filter(ReviewsModel.del_flag == 0,
                    ReviewsModel.reviews_group_code == query_model.group_id if query_model.group_id else True,
                    ReviewsModel.is_hot == query_model.is_hot if query_model.is_hot else True) \
            .order_by(ReviewsModel.release_time.desc()) \
            .offset(offset).limit(query_model.page_size).all()

        return reviews_list

    @classmethod
    def get_reviews_list_no_paginated(cls, db: Session, query_model: ReviewsListQueryModel) \
            -> Optional[List]:
        """
        点评列表查询方法
        :param db: ORM
        :param query_model: 查询参数集
        :return: 不分页列表
        """

        if query_model.keyword != '':
            like_condition = or_(ReviewsModel.reviews_title.like('%' + query_model.keyword + '%'),
                                 ReviewsModel.reviews_content.like('%' + query_model.keyword + '%'))
            reviews_list = db.query(ReviewsModel).filter(like_condition).filter(ReviewsModel.del_flag == False) \
                .order_by(ReviewsModel.release_time.desc()).all()

            return reviews_list
        else:
            query = db.query(ReviewsModel) \
                .filter(ReviewsModel.del_flag == False,
                        ReviewsModel.reviews_group_code == query_model.group_id if query_model.group_id else True,
                        ReviewsModel.is_hot == query_model.is_hot if query_model.is_hot else True)

            reviews_list = query.order_by(ReviewsModel.release_time.desc()).all()
            return reviews_list

    @classmethod
    def get_reviews_by_id(cls, db: Session, reviews_id: str) -> Optional[ReviewsModel]:
        """
        通过点评ID获取点评详情
        :param db: ORM对象
        :param reviews_id: 点评ID
        :return: 单条点评详情
        """
        reviews = db.query(ReviewsModel).filter(ReviewsModel.reviews_id == reviews_id).first()

        return reviews

    @classmethod
    def create_reviews(cls, db: Session, reviews: ReviewsModel) -> ReviewsModel:
        """
        新建点评
        :param db:
        :param reviews:
        :return:
        """
        new_reviews = reviews
        try:
            db.add(new_reviews)
            db.commit()
            return new_reviews.reviews_id
        except Exception as e:
            db.rollback()
            logger.error(e)

    @classmethod
    def update_reviews_by_images(cls, db: Session, reviews: ReviewsModel):
        # 因为ReviewsModel的表中存在ARRAY字段，所以在update这个字段时，要用以下的方法，不可以直接update()，会报Attribute ‘items’异常
        try:
            cur_model = db.query(ReviewsModel).filter(ReviewsModel.reviews_id == reviews.reviews_id).first()

            cur_model.reviews_images = reviews.reviews_images
            flag_modified(cur_model, 'reviews_images')

            cur_model.primary_image = reviews.primary_image
            flag_modified(cur_model, 'primary_image')

            db.merge(cur_model)
            db.flush()
            db.commit()
            return reviews.reviews_id
        except Exception as e:
            db.rollback()
            logger.error(e)

    @classmethod
    def update_reviews_liker(cls, db: Session, reviews_id: str, liker_num: int):
        """
        更新点评实体的liker_num
        :param db:
        :param reviews_id:
        :param liker_num:
        """
        try:
            cur_model = db.query(ReviewsModel).filter(ReviewsModel.reviews_id == reviews_id).first()
            cur_model.liker_num = liker_num
            flag_modified(cur_model, 'liker_num')

            db.merge(cur_model)
            db.flush()
            db.commit()
        except Exception as e:
            db.rollback()
            logger.error(e)

    @classmethod
    def delete_look_data(cls, db: Session):
        db.delete(db.query(ReviewsLookModel).all())
        db.flush()

    @classmethod
    def batch_add_looks(cls, db: Session, look_list: List[ReviewsLookModel]) -> bool:
        if len(look_list) == 0:
            return False
        try:
            cls.delete_look_data(db)
            stmt = insert(ReviewsLookModel).values(look_list)
            db.execute(stmt)
            db.commit()
            return True
        except SQLAlchemyError as e:
            db.rollback()
            raise e

    @classmethod
    def add_look(cls, db: Session, reviews_id) -> bool:
        try:
            look = db.query(ReviewsLookModel).filter(ReviewsLookModel.reviews_id == reviews_id).first()
            if look is None:
                look = ReviewsLookModel()
                look.reviews_id = reviews_id
                look.look_total = 1
                look.last_update_time = datetime.now()
                db.add(look)
            else:
                look.last_update_time = datetime.now()
                look.look_total += 1
                db.merge(look)
            db.commit()
            return True
        except SQLAlchemyError as e:
            db.rollback()
            raise e
